var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({ port: 8181 });//服务端口8181

// 房间
const rooms = [];
// 用户
const users = [];

/**
 * 初始化房间
 */
const initRooms = () => {
    for (let index = 1; index <= 20; index++) {
        rooms.push({
            id: index,
            name: index + '号房间',
            users: [],  //对战双方
            history: [] //历史记录
        });
    }
}

initRooms();

// 用户ID
let uid = 0;

/**
 * 发送消息
 */
const send = (user, msg) => {
    user = user.ws ? user : findUser(user);
    user.ws.send(JSON.stringify(msg));
}

/**
 * 根据用户找房间
 */
const findRoomByUser = (user) => rooms.find(c => c.users.some(d => d.uid === user.uid));

/**
 * 找对手
 */
const findOpponent = (user, room) => room.users.find(c => c.uid !== user.uid);

/**
 * 查找用户
 */
const findUser = (user) => users.find(c => c.uid === (typeof user === 'number' ? user : user.uid));

/**
 * 拷贝用户
 */
const cloneUser = ({ name, uid }) => ({ name, uid });

/**
 * 删除房间用户
 */
const deleteRoomUser = (user, room) => {
    const index = room.users.findIndex(c => c.uid === user.uid);
    room.users.splice(index, 1);
    for (const user of users) {
        getRoomList(user);
    }
}

/**
 * 加入房间
 */
const joinRoom = (msg, user) => {
    const room = rooms.find(c => c.id === msg.id);  //查找房间
    if (!room) {
        return send(user, { type: 'join', msg: '房间不存在' });
    }
    if (room.users.length > 1) {
        return send(user, { type: 'join', msg: '房间已满' });
    }
    try {
        // 如果满人则开始
        room.users.push(cloneUser(user));
        if (room.users.length === 1) {
            return send(user, { type: 'join' });
        }
        room.history.length = 0;    //清空以前的历史记录
        // 随机确定谁是红方，红方先手
        const index = Math.floor(Math.random() * 10 % 2);
        for (let i = 0; i < room.users.length; i++) {
            const item = room.users[i];
            send(item, { type: 'start', room, red: index === i, trun: index === i, opponent: room.users[Math.abs(i - 1)] });
        }
    } catch (error) {
    } finally {
        for (const user of users) {
            getRoomList(user);
        }
    }
}

/**
 * 走棋
 */
const go = (msg, user) => {
    try {
        const room = findRoomByUser(user);
        const opponent = findOpponent(user, room);   //对手
        // 下一步
        const next = {
            qizi: msg.qizi, //什么棋子
            uid: user.uid,
            from: msg.from,   //从哪里来的
            xy: msg.xy, //位置
            kill: msg.kill  //吃掉的棋
        }
        room.history.push(next);
        next.type = 'go';
        // 吃将则输了
        if (msg.code === 'jiang') {
            send(user, {
                ...next,
                history: room.history,
                self: true,
                result: 'win'
            });
            return send(opponent, {
                ...next,
                history: room.history,
                self: false,
                result: 'lost'
            });
        }
        send(user, {
            self: true,
            history: room.history,
            trun: false,
            ...next
        });
        send(opponent, {
            trun: true,
            history: room.history,
            self: false,
            ...next
        });
    } catch (error) {
        console.log(error);
    }
}

// 询问返回
const canback = (user) => {
    try {
        const room = findRoomByUser(user);
        const opponent = findOpponent(user, room);   //对手
        if (!room.history.length) {
            return send(user, { type: 'backresult', msg: '已经到了第一步了，已无法悔棋' });
        }
        // 如果有对手则发指令
        opponent && send(opponent, {
            type: 'canback'
        });
    } catch (error) {
    }
}

/**
 * 退出游戏
 */
const exitGame = (user) => {
    try {
        const room = findRoomByUser(user);
        deleteRoomUser(user, room);
        const opponent = findOpponent(user, room);   //对手
        // 如果有对手则发送退出指令
        opponent && send(opponent, {
            type: 'exit'
        });
        for (const user of users) {
            getRoomList(user);
        }
    } catch (error) {
    }
}

/**
 * 获取房间列表
 */
const getRoomList = (user) => {
    try {
        const _rooms = rooms.map(c => ({ ...c, history: undefined }));
        send(user, {
            type: 'rooms',
            rooms: _rooms
        });
    } catch (error) {
        console.log(error);
    }
}

/**
 * 悔棋
 */
const back = (msg, user) => {
    try {
        const room = findRoomByUser(user);
        const opponent = findOpponent(user, room);   //对手
        if (!msg.can) {
            return send(opponent, { type: 'backresult', msg: '对方拒绝悔棋' });
        }
        const lastItem = room.history.pop(); //最后一次的记录
        // 如果有对手则发送退出指令
        opponent && send(opponent, {
            ...lastItem,
            type: 'backresult',
            history: room.history
        });
        send(user, {
            ...lastItem,
            type: 'backresult',
            history: room.history
        });
    } catch (error) {
        console.log(error);
    }
}

/**
 * 处理指令
 */
const handleCommand = (msg, user) => {
    switch (msg.type) {
        case 'join':
            return joinRoom(msg, user);
        case 'go':
            return go(msg, user);
        case 'exit':
            return exitGame(user);
        case 'rooms':
            return getRoomList(user);
        case 'canback':
            return canback(user);
        case 'back':
            return back(msg, user);
    }
}

wss.on('connection', function (ws, req) {
    const name = decodeURI(req.url?.split('=')?.pop() ?? '无名');
    const user = {
        uid: ++uid,
        name,
        ws
    };
    users.push(user);
    send(user, {
        type: 'login',
        name,
        uid: user.uid
    });
    ws.on('close', function () {
        users.splice(users.indexOf(user), 1);
        exitGame(user);
    });
    ws.on('message', function (message) {
        try {
            var msg = JSON.parse(message.toString());
            handleCommand(msg, user);
        } catch (error) { }
    });
});